package com.baizhi.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * description:手动封装通用的sql方法
 *
 * @author RenShiWei
 * Date: 2020/12/29 15:15
 **/
public class LowJdbcUtil {

    private static String driver = "com.mysql.cj.jdbc.Driver";
    private static String url = "jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true" +
            "&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true";
    private static String user = "root";
    private static String password = "rwby1234";

    private static Connection conn = null;
    private static Statement stmt = null;
    private static ResultSet rs = null;
    private static PreparedStatement ptmt = null;


    /**
     * 连接数据库
     */
    public static Connection getConn() {
        // 1.注册 JDBC 驱动
        try {
            Class.forName(driver);
            // 2.打开链接
            conn = DriverManager.getConnection(url, user, password);
            return conn;
        } catch (Exception e) {
            System.out.println("数据库连接失败");
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 关闭数据库的方法
     */
    public static void closeConn() {
        try {
            if (rs != null) {
                rs.close();
            }
            rs = null;
            if (stmt != null) {
                stmt.close();
            }
            stmt = null;
            if (ptmt != null) {
                ptmt.close();
            }
            ptmt = null;
            if (conn != null) {
                conn.close();
            }
            conn = null;
        } catch (Exception e) {
            System.out.println("关闭数据库连接失败");
            e.printStackTrace();
        }
    }


    /*
     * =======================通用的查询方法======================
     */

    /**
     * 利用object...传参 公共的select方法(精确查询) 返回类型为Vector<Vector<Object>> 遍历Object类型的结果集
     */
    public static Vector<Vector<Object>> queryExactPublic(String sql, Object... parameter) {
        Vector<Vector<Object>> dataVector = new Vector<Vector<Object>>(); // 存储所有数据，里面每个小的Vector是存单行的
        //连接mysql
        getConn();
        try {
            ptmt = conn.prepareStatement(sql);
            for (int i = 0; i < parameter.length; i++) {
                ptmt.setObject(i + 1, parameter[i]);
            }
            ResultSet rs = ptmt.executeQuery();
            while (rs.next()) {
                // 就是这个存单行的，最后放到上面的大的Vector里面
                Vector<Object> vec = new Vector<>();
                // 遍历数据库中每列的结果集 column需要遍历的列数
                for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
                    vec.add(rs.getObject(i));
                }
                dataVector.add(vec);
            }
        } catch (Exception e) {
            System.out.println("数据库查询操作失败");
            e.printStackTrace();
        }
        // 关闭连接
        closeConn();
        return dataVector;
    }

    /**
     * description:通用查询，返回list
     *
     * @param sql    sql语句
     * @param clazz  类的对象
     * @param params 参数列表
     * @return list
     * @author RenShiWei
     * Date: 2020/12/31 11:36
     */
    public static <K> List<K> queryForList(String sql, Class<K> clazz, Object... params) {
        List<K> list = new ArrayList<>();
        //获取传入类中的方法
        Method[] methods = clazz.getMethods();
        //设置一个方法的list集合，下面将方法放入其中，以便调用
        List<Method> setMethodList = new ArrayList<>();
        //类中有许多方法，过滤一些方法，获取自己想要的方法
        for (int i = 0; i < methods.length; i++) {
            //判断方法名字中是否有set这个提取
            if (methods[i].getName().contains("set")) {
                //将方法添加到list中
                setMethodList.add(methods[i]);
            }
        }

        //创建字符串string集合，获取下面的字段名存入
        List<String> fieldname = new ArrayList<>();
        //获取类中的属性，其属性对应数据库中的字段
        Field[] fields = clazz.getDeclaredFields();
        //循环将字段中的名字首个变大写
        for (int i = 0; i < fields.length; i++) {
            //设置成允许操作属性。
            fields[i].setAccessible(true);
            //获取名字
            String field = fields[i].getName();
            //首字母变大小写，存入fieldname集合
            fieldname.add(upperCase(field));
        }

        //连接mysql
        getConn();
        try {
            ptmt = conn.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                ptmt.setObject(i + 1, params[i]);
            }
            ResultSet rs = ptmt.executeQuery();
            //获取得到结果集(rs)的结构，比如字段数、字段名等。
            ResultSetMetaData resultSetMetaData = rs.getMetaData();
            while (rs.next()) {
                //创建一个传入类对象user
                K obj = (K) clazz.newInstance();
                //遍历方法的集合
                for (Method m : setMethodList) {
                    //遍历字段的集合
                    for (int i = 0; i < fields.length; i++) {
                        //方法和字段作比较，查看方法名中是否含有这个字段名，两者匹配
                        if (m.getName().contains("set" + fieldname.get(i))) {
                            Object value = rs.getObject(resultSetMetaData.getColumnName(i + 1));
                            //获取这个字段的类型，以便去储存这个值的类型
                            Class<?> type = fields[i].getType();

                            m.invoke(obj, value);
                        }
                    }
                }
                list.add(obj);
            }
        } catch (Exception e) {
            System.out.println("数据库查询操作失败");
            e.printStackTrace();
        }
        // 关闭连接
        closeConn();
        return list;
    }


    /**
     * 通用的增删改的方法
     */
    public static void updatePublic(String sql, Object... parameter) {
        //连接mysql
        getConn();
        try {
            ptmt = conn.prepareStatement(sql);
            for (int i = 0; i < parameter.length; i++) {
                ptmt.setObject(i + 1, parameter[i]);
            }
            int count = ptmt.executeUpdate();
            System.out.println("数据库执行了" + count + "条操作");
        } catch (Exception e) {
            System.out.println("数据库增删改失败");
            e.printStackTrace();
        }
        // 关闭连接
        closeConn();
    }

    public static int updatePublic2(String sql, Object... parameter) {
        int count = 0;
        //连接mysql
        getConn();
        try {
            ptmt = conn.prepareStatement(sql);
            for (int i = 0; i < parameter.length; i++) {
                ptmt.setObject(i + 1, parameter[i]);
            }
            count = ptmt.executeUpdate();
            System.out.println("数据库执行了" + count + "条操作");
        } catch (Exception e) {
            System.out.println("数据库增删改失败");
            e.printStackTrace();
        }
        // 关闭连接
        closeConn();
        return count;
    }
    /**
     * 利用object...传参 公共的select方法(模糊查询) 返回类型为Vector<Vector<Object>> 遍历Object类型的结果集
     */
    public static Vector<Vector<Object>> queryDimPublic(String sql, Object... parameter) {
        Vector<Vector<Object>> dataVector = new Vector<Vector<Object>>(); // 存储所有数据，里面每个小的Vector是存单行的
        getConn();
        try {
            ptmt = conn.prepareStatement(sql);
            for (int i = 0; i < parameter.length; i++) {
                ptmt.setObject(i + 1, "%" + parameter[i] + "%");
            }
            ResultSet rs = ptmt.executeQuery();
            while (rs.next()) {
                Vector<Object> vec = new Vector<Object>();// 就是这个存单行的，最后放到上面的大的Vector里面
                // 遍历数据库中每列的结果集 column需要遍历的列数
                for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
                    vec.add(rs.getObject(i));
                }
                dataVector.add(vec);
            }
        } catch (Exception e) {
            System.out.println("数据库模糊查询失败");
            e.printStackTrace();
        }
        // 关闭连接
        closeConn();
        return dataVector;
    }

    /**
     * 通用的数据是否存在方法
     * 利用object...预处理 查询目标记录是否在数据库中存在
     */
    public static boolean exist(String sql, Object... parameter) {
        boolean exist = false;
        // 调用数据库的连接方法
        Connection conn = getConn();
        try {
            assert conn != null;
            PreparedStatement ptmt = conn.prepareStatement(sql);
            for (int i = 0; i < parameter.length; i++) {
                ptmt.setObject(i + 1, parameter[i]);
            }
            ResultSet rs = ptmt.executeQuery();
            while (rs.next()) {
                exist = true;
            }
        } catch (Exception e) {
            System.out.println("数据库查询失败");
            e.printStackTrace();
        }
        // 关闭连接
        closeConn();
        return exist;
    }

    /**
     * description:字段名首字母转大写
     *
     * @author RenShiWei
     * Date: 2020/12/31 10:50
     */
    public static String upperCase(String str) {
        //先将字符串转换为字符数组
        char[] ch = str.toCharArray();
        //将数组的第一个元素     即字符串首字母，进行ASCII 码前移，ASCII 中大写字母从65开始，小写字母从97开始，所以这里减去32。
        if (ch[0] >= 'a' && ch[0] <= 'z') {
            ch[0] = (char) (ch[0] - 32);
        }
        return new String(ch);
    }

}

